{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "v8KR9V4Hy-vw"
      },
      "source": [
        "# Imports"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "both",
        "colab": {},
        "colab_type": "code",
        "id": "idfu7sA0vExR"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import\n",
        "from __future__ import division\n",
        "from __future__ import print_function\n",
        "\n",
        "import sys\n",
        "assert sys.version_info.major == 3\n",
        "import os\n",
        "\n",
        "add_paths = True\n",
        "if add_paths:\n",
        "  sys.path.insert(0, os.path.join(os.path.abspath(os.getcwd()), '..', '..'))\n",
        "  sys.path.insert(\n",
        "      0,\n",
        "      os.path.join(os.path.abspath(os.getcwd()), '..', '..', 'build', 'python'))\n",
        "  import pyspiel\n",
        "\n",
        "\n",
        "from open_spiel.python.algorithms import cfr\n",
        "from open_spiel.python.algorithms import exploitability\n",
        "from open_spiel.python.algorithms import expected_game_score\n",
        "from open_spiel.python.bots import uniform_random\n",
        "from open_spiel.python.visualizations import treeviz"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "HLXNc0ZCvExt"
      },
      "outputs": [],
      "source": [
        "games_list = pyspiel.registered_names()\n",
        "\n",
        "print(\"Registered games:\")\n",
        "print(games_list)\n",
        "\n",
        "game = pyspiel.load_game(\"universal_poker\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "vqyfMHs2vEx7"
      },
      "outputs": [],
      "source": [
        "\"\"\"Test that Python and C++ bots can be called by a C++ algorithm.\"\"\"\n",
        "\n",
        "from absl.testing import absltest\n",
        "import numpy as np\n",
        "\n",
        "from open_spiel.python.bots import uniform_random\n",
        "\n",
        "game = pyspiel.load_game(\"leduc_poker\")\n",
        "bots = [\n",
        "    pyspiel.make_uniform_random_bot(0, 1234),\n",
        "    uniform_random.UniformRandomBot(1, np.random.RandomState(4321)),\n",
        "]\n",
        "results = np.array([\n",
        "    pyspiel.evaluate_bots(game.new_initial_state(), bots, iteration)\n",
        "    for iteration in range(10000)\n",
        "])\n",
        "leduc_average_results = np.mean(results, axis=0)\n",
        "print(leduc_average_results)\n",
        "\n",
        "game = pyspiel.load_game(\"universal_poker\")\n",
        "bots = [\n",
        "    pyspiel.make_uniform_random_bot(0, 1234),\n",
        "    uniform_random.UniformRandomBot(1, np.random.RandomState(4321)),\n",
        "]\n",
        "results = np.array([\n",
        "    pyspiel.evaluate_bots(game.new_initial_state(), bots, iteration)\n",
        "    for iteration in range(10000)\n",
        "])\n",
        "universal_poker_average_results = np.mean(results, axis=0)\n",
        "print(universal_poker_average_results)\n",
        "\n",
        "#np.testing.assert_allclose(universal_poker_average_results, leduc_average_results, atol=0.1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "RhI6kVnkvEyE"
      },
      "outputs": [],
      "source": [
        "universal_poker_kuhn_limit_3p = \"\"\"\\\n",
        "GAMEDEF\n",
        "limit\n",
        "numPlayers = 3\n",
        "numRounds = 1\n",
        "blind = 1 1 1\n",
        "raiseSize = 1\n",
        "firstPlayer = 1\n",
        "maxRaises = 1\n",
        "numSuits = 1\n",
        "numRanks = 4\n",
        "numHoleCards = 1\n",
        "numBoardCards = 0\n",
        "END GAMEDEF\n",
        "\"\"\"\n",
        "\n",
        "game = pyspiel.load_game(\n",
        "    \"universal_poker\",\n",
        "    {\"gamedef\": pyspiel.GameParameter(universal_poker_kuhn_limit_3p)})\n",
        "str(game)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "lpLJhzBEvEyM"
      },
      "outputs": [],
      "source": [
        "# Compare exloitability for two games\n",
        "players = 2\n",
        "iterations = 10\n",
        "print_freq = 1\n",
        "\n",
        "def compare_exploitability(game_1, game_2):\n",
        "  cfr_solver_1 = cfr.CFRSolver(game_1)\n",
        "  cfr_solver_2 = cfr.CFRSolver(game_2)\n",
        "  for i in range(iterations):\n",
        "    cfr_solver_1.evaluate_and_update_policy()\n",
        "    cfr_solver_2.evaluate_and_update_policy()\n",
        "    if i % print_freq == 0:\n",
        "      conv_1 = exploitability.exploitability(game_1,\n",
        "                                             cfr_solver_1.average_policy())\n",
        "      conv_2 = exploitability.exploitability(game_2,\n",
        "                                             cfr_solver_2.average_policy())\n",
        "\n",
        "      print(\"Iteration {} exploitability of the  {} vs: {}\".format(\n",
        "          i, conv_1, conv_2))\n",
        "\n",
        "  print(\"Final exploitability is {} vs {}\".format(conv_1, conv_2))\n",
        "\n",
        "\n",
        "game_1 = pyspiel.load_game(\"kuhn_poker\",\n",
        "                           {\"players\": pyspiel.GameParameter(2)})\n",
        "\n",
        "universal_poker_kuhn_limit_2p = \"\"\"\\\n",
        "GAMEDEF\n",
        "limit\n",
        "numPlayers = 2\n",
        "numRounds = 1\n",
        "blind = 1 1\n",
        "raiseSize = 1\n",
        "firstPlayer = 1\n",
        "maxRaises = 1\n",
        "numSuits = 1\n",
        "numRanks = 3\n",
        "numHoleCards = 1\n",
        "numBoardCards = 0\n",
        "END GAMEDEF\n",
        "\"\"\"\n",
        "game_2 = pyspiel.load_game(\n",
        "    \"universal_poker\",\n",
        "    {\"gamedef\": pyspiel.GameParameter(universal_poker_kuhn_limit_2p)})\n",
        "compare_exploitability(game_1, game_2)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "0Zltqy5PNM8P"
      },
      "outputs": [],
      "source": [
        "game_1 = pyspiel.load_game(\"leduc_poker\",\n",
        "                           {\"players\": pyspiel.GameParameter(2)})\n",
        "# Taken verbatim from the linked paper above: \"In Leduc hold'em, the deck\n",
        "# consists of two suits with three cards in each suit. There are two rounds.\n",
        "# In the first round a single private card is dealt to each player. In the\n",
        "# second round a single board card is revealed. There is a two-bet maximum,\n",
        "# with raise amounts of 2 and 4 in the first and second round, respectively.\n",
        "# Both players start the first round with 1 already in the pot.\n",
        "\n",
        "universal_poker_leduc_limit_2p = \"\"\"\\\n",
        "GAMEDEF\n",
        "limit\n",
        "numPlayers = 2\n",
        "numRounds = 2\n",
        "blind = 1 1\n",
        "raiseSize = 1 1\n",
        "firstPlayer = 1 1\n",
        "maxRaises = 2 2\n",
        "raiseSize = 2 4\n",
        "numSuits = 2\n",
        "numRanks = 3\n",
        "numHoleCards = 1 0\n",
        "numBoardCards = 0 1\n",
        "END GAMEDEF\n",
        "\"\"\"\n",
        "game_2 = pyspiel.load_game(\n",
        "    \"universal_poker\",\n",
        "    {\"gamedef\": pyspiel.GameParameter(universal_poker_leduc_limit_2p)})\n",
        "compare_exploitability(game_1, game_2)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "zk4rz8mvvEyb"
      },
      "outputs": [],
      "source": [
        "game = \"universal_poker\"\n",
        "out = \"/tmp/gametree.png\"\n",
        "prog = \"dot\"\n",
        "group_infosets = False\n",
        "group_terminal = False\n",
        "verbose = False\n",
        "\n",
        "\n",
        "def _zero_sum_node_decorator(state):\n",
        "  \"\"\"Custom node decorator that only shows the return of the first player.\"\"\"\n",
        "  attrs = treeviz.default_node_decorator(state)  # get default attributes\n",
        "  if state.is_terminal():\n",
        "    attrs[\"label\"] = str(int(state.returns()[0]))\n",
        "  return attrs\n",
        "\n",
        "\n",
        "game = pyspiel.load_game(\n",
        "    game, {\"gamedef\": pyspiel.GameParameter(universal_poker_kuhn_limit_2p)})\n",
        "game_type = game.get_type()\n",
        "\n",
        "if game_type.dynamics != pyspiel.GameType.Dynamics.SEQUENTIAL:\n",
        "  raise ValueError(\"Game must be sequential, not {}\".format(game_type.dynamics))\n",
        "\n",
        "if (game_type.utility == pyspiel.GameType.Utility.ZERO_SUM and\n",
        "    game.num_players() == 2):\n",
        "  gametree = treeviz.GameTree(\n",
        "      game,\n",
        "      node_decorator=_zero_sum_node_decorator,\n",
        "      group_infosets=group_infosets,\n",
        "      group_terminal=group_terminal)\n",
        "else:\n",
        "  gametree = treeviz.GameTree(game)  # use default decorators\n",
        "\n",
        "if verbose:\n",
        "  logging.info(\"Game tree:\\n%s\", gametree.to_string())\n",
        "\n",
        "gametree.draw(out, prog=prog)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4rvvGu65M1jk"
      },
      "outputs": [],
      "source": [
        ""
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "last_runtime": {
        "build_target": "",
        "kind": "local"
      },
      "name": "test_universal_poker.ipynb",
      "provenance": [
        {
          "file_id": "1ZX9X01BBrKZp5EAIEXTLwzxuTbEj0rTJ",
          "timestamp": 1575292378817
        }
      ]
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.6.7"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
